/**
   A class that calculates grades averages for a class.
*/
public class GradeAnalyzer {
	
	// Class grade threshold constants
	private final int APLUS = 98;
	private final int A = 92;
	private final int AMINUS = 90;
	private final int BPLUS = 88;
	private final int B = 82;
	private final int BMINUS = 80;
	private final int CPLUS = 78;
	private final int C = 72;
	private final int CMINUS = 70;
	private final int D = 60;
	private final int F = 59;
	private final int MAXGRADE = 110;
	private final int MINGRADE = 0;
	
	// Counts of each letter grade
	private int numberOfAPluses = 0;
	private int numberOfAs = 0;
	private int numberOfAMinuses = 0;
	private int numberOfBPluses = 0;
	private int numberOfBs = 0;
	private int numberOfBMinuses = 0;
	private int numberOfCPluses = 0;
	private int numberOfCs = 0;
	private int numberOfCMinuses = 0;
	private int numberOfDs = 0;
	private int numberOfFs = 0;
	
	private int totalGradesEntered = 0;
	private double sumOfGradesEntered = 0;
	private double sumOfSquareOfGradesEntered = 0;
	private double averageOfGradesEntered = 0;
	private double standardDeviationOfGradesEntered = 0;
	
	
	/**
    Adds a valid grade to the list of grades.
    @param the grade percentage
	*/
	public void addGrade(double aGrade)
	{
		// If the grade is valid, increment total grades by 1, add it to the current grade total, and
		// add the square of the grade to the current total of squared grades.  Also determines the
		// letter grade and increments the letter grade count.
		if (isValidGrade(aGrade))
		{
			totalGradesEntered++;
			sumOfGradesEntered = sumOfGradesEntered + aGrade;
			sumOfSquareOfGradesEntered = sumOfSquareOfGradesEntered + (aGrade * aGrade);
			if ( (int) aGrade >= APLUS)
			{
				numberOfAPluses++;
			}
			else if ((int) aGrade < APLUS && (int) aGrade >= A)
			{
				numberOfAs++;
			}
			else if ((int) aGrade < A && (int) aGrade >= AMINUS)
			{
				numberOfAMinuses++;
			}
			else if ((int) aGrade < AMINUS && (int) aGrade >= BPLUS)
			{
				numberOfBPluses++;
			}
			else if ((int) aGrade < BPLUS && (int) aGrade >= B)
			{
				numberOfBs++;
			}
			else if ((int) aGrade < B && (int) aGrade >= BMINUS)
			{
				numberOfBMinuses++;
			}
			else if ((int) aGrade < BMINUS && (int) aGrade >= CPLUS)
			{
				numberOfCPluses++;
			}
			else if ((int) aGrade < CPLUS && (int) aGrade >= C)
			{
				numberOfCs++;
			}
			else if ((int) aGrade < C && (int) aGrade >= CMINUS)
			{
				numberOfCMinuses++;
			}
			else if ((int) aGrade < CMINUS && (int) aGrade >= D)
			{
				numberOfDs++;
			}
			else if ((int) aGrade <= F)
			{
				numberOfFs++;
			}
		}
	}
	
	
	/**
    Determines if a grade is valid by making sure it lies between the minimum and maximum grades.
    @param the grade percentage
    @return boolean
	*/
	public boolean isValidGrade(double aGrade)
	{
		if (aGrade >= MINGRADE && aGrade <= MAXGRADE)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	
	
	/**
    Analyzes the grades by calculating the average of the grades entered and the standard deviation
    */
	public void analyzeGrades()
	{
		// Grade averages
		this.averageOfGradesEntered = this.sumOfGradesEntered / ((double) this.totalGradesEntered);
		// Implementation of the 2nd standard deviation formula from page 268 of Big Java
		double sumOfGradesEnteredSquared = this.sumOfGradesEntered * this.sumOfGradesEntered;
        double standardDeviationDenominator = ((double) this.totalGradesEntered) - 1;
        double standardDeviationNumerator = (this.sumOfSquareOfGradesEntered - ((1 / (double) this.totalGradesEntered) * sumOfGradesEnteredSquared));
        double standardDeviationFraction = standardDeviationNumerator / standardDeviationDenominator;
        this.standardDeviationOfGradesEntered = Math.sqrt(standardDeviationFraction);
	}
	
	
	/**
    Converts all grading information to a string.
    @return a string to print to the console
	*/
	public String toString()
	{
		String outputString = "";
		if (this.totalGradesEntered >= 2)
		{
			outputString = "You entered " + totalGradesEntered + " valid grades from 0 to 110. ";
			outputString = outputString + "Invalid grades are ignored!\n\n";
			outputString = outputString + "The average = " + (int) averageOfGradesEntered;
			outputString = outputString + " with a standard deviation = " + (int) standardDeviationOfGradesEntered + "\n\n";
			outputString = outputString + "The grade distribution is:\n\n";
			outputString = outputString + "A+ = " + numberOfAPluses + "\n";
			outputString = outputString + "A  = " + numberOfAs + "\n";
			outputString = outputString + "A- = " + numberOfAMinuses + "\n";
			outputString = outputString + "B+ = " + numberOfBPluses + "\n";
			outputString = outputString + "B  = " + numberOfBs + "\n";
			outputString = outputString + "B- = " + numberOfBMinuses + "\n";
			outputString = outputString + "C+ = " + numberOfCPluses + "\n";
			outputString = outputString + "C  = " + numberOfCs + "\n";
			outputString = outputString + "C- = " + numberOfCMinuses + "\n";
			outputString = outputString + "D  = " + numberOfDs + "\n";
			outputString = outputString + "F  = " + numberOfFs;
		}
		else
		{
			outputString = "You did not enter enough grades to analyze.  Please enter at least 2 valid grades";
		}
		return outputString;
	}
}